package com.zmn.brs.business.impl.order;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zmn.brs.business.impl.base.BaseBServiceImpl;
import com.zmn.brs.business.interfaces.dingtalk.DingTalkBService;
import com.zmn.brs.business.interfaces.order.OrderQuantityBService;
import com.zmn.brs.common.constant.RedisKeyConst;
import com.zmn.brs.common.enums.PlatEnum;
import com.zmn.brs.common.enums.SceneTypeEnum;
import com.zmn.brs.dubbo.constant.DubboConsts;
import com.zmn.brs.model.bo.rule.CacheThresholdBO;
import com.zmn.brs.model.entity.record.EventRecord;
import com.zmn.brs.model.vo.rule.QuantityRuleVO;
import com.zmn.brs.model.vo.rule.common.OrderRuleVO;
import com.zmn.brs.services.interfaces.record.EventRecordService;
import com.zmn.brs.utils.BrsUtil;
import com.zmn.common.dto2.ResponseDTO;
import com.zmn.common.utils.date.DateUtil;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.common.utils.string.StringUtil;
import com.zmn.consts.GlobalConsts;
import com.zmn.oms.common.dto.QueueOrderNodeNotifyDTO;
import com.zmn.plat.common.dto.company.CompanyDRO;
import com.zmn.plat.dubbo.interfaces.company.BaseCompanyListRemoteService;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 描述： 订单监控整体单量实现
 *
 * @author chongw
 * @since 2021-06-26 9:56
 */
@Slf4j
@Service
public class OrderQuantityBServiceImpl extends BaseBServiceImpl<OrderRuleVO> implements OrderQuantityBService {

    final static String TAG = "订单监控整体单量实现";

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Resource
    private EventRecordService eventRecordService;

    @Resource
    private DingTalkBService dingTalkBService;

    @Reference(version = DubboConsts.INTERFACE_VERSION, check = false)
    BaseCompanyListRemoteService baseCompanyListRemoteService;

    /**
     * 计算当天整体单量
     * eventType 事件类型
     * @param queueOrderNodeNotifyDTO
     * @return
     */
    @Override
    public Boolean compute(Integer eventType, QueueOrderNodeNotifyDTO queueOrderNodeNotifyDTO){
        try {
            //只监控啄木鸟平台订单
            if(!PlatEnum.ZMN_PLAT.getCode().equals(queueOrderNodeNotifyDTO.getPlat())){
                return false;
            }
            //判断城市是否为空
            if (NumberUtil.isNullOrZero(queueOrderNodeNotifyDTO.getCityId())) {
                return false;
            }
            //城市ID
            Integer cityId = queueOrderNodeNotifyDTO.getCityId();
            //获取阈值配置
            CacheThresholdBO configData = this.getCityThreshold(eventType, cityId);
            if(configData == null){
                return false;
            }
            //根据服务商ID查询所属子公司ID
            ResponseDTO<CompanyDRO> responseDTO = baseCompanyListRemoteService.getCompanyByCompanyId(queueOrderNodeNotifyDTO.getCompanyId());
            if(!responseDTO.isSuccess()){
                return false;
            }
            if(responseDTO.getData() == null){
                log.error("[{}], 当前服务器未找到所属子公司，服务商ID：{}，订单ID：{}", TAG, queueOrderNodeNotifyDTO.getCompanyId(), queueOrderNodeNotifyDTO.getOrderId());
                return false;
            }
            CompanyDRO companyDRO = responseDTO.getData();
            if(BrsUtil.JXJ_ORG_THR_ID.equals(companyDRO.getOrgThrId())){
                log.error("[{}], 当前订单是家修匠子公司，不进行监控！！！订单ID：{}", TAG, queueOrderNodeNotifyDTO.getOrderId());
                return false;
            }
            //缓存推送数据redis key
            String todayRedisKey = RedisKeyConst.getTodayRedisKey(eventType, DateUtil.getNowFormatted(DateUtil.FORMAT_DATE2));
            //累计工程师收款未支付金额
            Long realValue = redisTemplate.opsForHash().increment(todayRedisKey, String.valueOf(cityId), 1L);
            redisTemplate.expire(todayRedisKey , 3 , TimeUnit.DAYS);

            //阈值
            Double thresholdValue = configData.getValue();
            //获取公共阈值 - 预警百分比
            Double percentValue = getCommonThresholdValue(eventType);
            Double ratioValue = percentValue/100;
            //预警值= 人单比阈值* 预警百分比
            Double warnValue = thresholdValue * ratioValue;
            //当天数据大于配置阈值，则预警
            if (realValue >= warnValue) {
                log.info("[{}], cityId：{}, 已触发订单整体单量监控预警！实际值：{}，阈值：{}，预警百分比：{}", TAG, cityId, realValue, thresholdValue, percentValue);
                JSONObject expandJson = new JSONObject();
                expandJson.put("realValue", realValue);
                expandJson.put("thresholdValue", thresholdValue);
                expandJson.put("percentValue", percentValue);
                EventRecord record = EventRecord.builder()
                        .objectId(queueOrderNodeNotifyDTO.getOrderId())
                        .thresholdId(configData.getThresholdId())
                        .sceneType(SceneTypeEnum.ORDER_TARGET.getTypeId())
                        .eventCode(configData.getEventCode())
                        .messageSend(GlobalConsts.NO)
                        .realName(configData.getThresholdName())
                        .expand(expandJson.toJSONString())
                        .createTime(DateUtil.getNow())
                        .monitorVersion(todayRedisKey)
                        .build();
                //保存事件监控数据
                Integer flag = eventRecordService.insert(record);
                if (flag > 0) {
                    log.info("[{}], cityId：{}，保存事件记录成功！！！", TAG, cityId);
                } else {
                    log.error("[{}], cityId：{}，保存事件记录失败！！！", TAG, cityId);
                }
            }
            return true;
        }catch (Exception e){
            log.error("[{}], 参数：{}，整体单量监控异常，异常信息：", TAG, JSON.toJSONString(queueOrderNodeNotifyDTO), e);
        }
        return false;
    }

    /**
     * 整体单量消息推送
     * @param eventType
     */
    public void pushJob(Integer eventType){
        Integer robotId = this.getRobotId(eventType);
        if(robotId == null){
            log.error("[{}], eventType：{}，未配置钉钉预警群消息机器人！！！", TAG, eventType);
            return;
        }
        //缓存推送数据redis key
        String todayRedisKey = RedisKeyConst.getTodayRedisKey(eventType, DateUtil.getNowFormatted(DateUtil.FORMAT_DATE2));
        //获取预警数据
        Map<Object, Object> todayData = Optional.ofNullable(redisTemplate.opsForHash().entries(todayRedisKey)).orElse(new HashMap<>());
        StringBuffer sb = new StringBuffer();
        todayData.forEach((k ,v) ->{
            Integer cityId = Integer.parseInt(k.toString());
            //获取阈值配置
            CacheThresholdBO configData = this.getCityThreshold(eventType, cityId);
            if(configData == null){
                return;
            }
            Integer realValue = Integer.parseInt(v.toString());
            //阈值
            Double thresholdValue = configData.getValue();
            //获取公共阈值 - 预警百分比
            Double percentValue = this.getCommonThresholdValue(eventType);
            Double ratioValue = percentValue/100;
            //预警值= 人单比阈值* 预警百分比
            Double warnValue = thresholdValue * ratioValue;
            if (realValue >= warnValue) {
                //获取当天城市推送缓存key
                String dingtalkCountKey = RedisKeyConst.getTodayQuantityDingtalkCountRedisKey(cityId);
                //设置推送次数
                Long count = redisTemplate.opsForValue().increment(dingtalkCountKey, 1L);
                //当推送次数大于5次，则不再推送
                if (count >= 5) {
                    log.info("[{}], cityId：{}，预警消息推送已超过5次，当前次数：{}", TAG, cityId, count);
                    return;
                }
                QuantityRuleVO vo = JSONObject.parseObject(configData.getThresholdValue(), QuantityRuleVO.class);
                sb.append(String.format("「%s.%s」实际单量 %s", vo.getProvinceName(), vo.getCityName(), realValue));
                sb.append("\n");
            }
        });
        if(sb != null && StringUtil.isNotBlank(sb.toString())){
            //获取公共阈值 - 预警百分比
            String percentValueStr = BrsUtil.formatDoubleToStr(getCommonThresholdValue(eventType));
            sb.insert(0, String.format("以下各城市单量已在峰值的%s%s以上，请时刻关注！\n",percentValueStr , "%"));
            sb.insert(0,"【订单量预警】\n");
            sb.append(String.format("%s数据", DateUtil.getNowFormatted().replace(" ", " 截止 ")));
            //发送钉钉群消息
            dingTalkBService.sendDingtalkGroup(robotId, sb.toString());
        }
    }

    /**
     * 根据城市Id获取配置阈值
     * @param eventType
     * @param cityId
     * @return
     */
    protected CacheThresholdBO getCityThreshold(Integer eventType , Integer cityId){
        //获取配置阈值key
        String configRedisKey = RedisKeyConst.getCacheRuleConfigRedisKey(eventType, cityId);
        //判断当前子公司及城市是否配置整体单量阈值
        if (!redisTemplate.hasKey(configRedisKey)) {
            log.error("[{}], 当前城市未配置整体单量阈值，cityId: {}", TAG, cityId);
            return null;
        }
        //配置的阈值
        CacheThresholdBO configData = this.getRuleConfigValue(configRedisKey);
        //判断配置是否配置阈值
        if (configData == null) {
            log.error("[{}], 当前城市整体单量配置为空，cityId: {}", TAG, cityId);
            return null;
        }
        //判断配置阈值是否为0或空
        if (NumberUtil.isNullOrZero(configData.getValue())) {
            log.error("[{}], 当前城市整体单量配置为空，cityId: {}，阈值：{}", TAG, cityId, configData.getValue());
            return null;
        }
        //获取当前规则状态
        Boolean statusFlag = this.checkStatus(configData);
        //状态是否已停用
        if(!statusFlag){
            return null;
        }
        return configData;
    }

}
